% !Mode:: "TeX:UTF-8"

\chapter{SpringBoot项目}

本项目为《软件工程综合实践》的第四个项目。要求开发基于SpringBoot + MyBatis + Vue的
前后端分离项目。要求学生强化对基于 SpringBoot + MyBatis + Vue 前后端分离项目
的需求分析、系统设计、编码和调试能力。

\section{需求分析}
\subsection{简介}
本项目是软件工程综合实践课程的第四个项目。根据智慧树平台上的项目任务书，
本项目为课程级贯穿项目中的第三个项目（JDBC项目、前端项目、javaWeb项目）的服务器端升级版。
即数据库结构与前端Vue没有任何变化，而服务器端由Servlet升级为SpringBoot。。
为了更好的协同合作，进行高效率的分工开发，做好需求分析也是非常重要的。


\subsubsection{环境搭建}
本项目因为是课程教学项目，所以对编程语言、平台和工具都有一定的要求，所以
本项目应该有以下技术架构：
\begin{itemize}
    \item Jdk8
    \item SpringBoot
    \item MyBatis
    \item MySql
    \item Vue
\end{itemize}

本项目采用以下开发工具：
\begin{itemize}
    \item HbuilderX
    \item STS（SpringToolSuite4）
    \item mysql
    \item Tomcat8.5 
    \item Maven
\end{itemize}

除此之外，为了方便开发和调试，我们还使用了Vscode，Apifox等开发工具。

\subsection{项目目标}
\subsubsection{目标}
\begin{itemize}
    \item 实现用户的登录注册与退出功能
    \item 实现用户的浏览商家、选择商家、选择食品、地址管理、下单、购物车、支付等业务和功能
\end{itemize}

\subsubsection{功能分析}
对于用户这个角色，有以下几个待解决的问题和对系统所需实现功能的期望（与项目三的功能大体一致）：
\begin{itemize}
    \item 能够通过手机号注册账户，一个手机号只能注册一次，且手机号必须符合规范
    \item 可通过手机号和密码登录系统，输入错误进行提示
    \item 用户可以退出自己的账号
    \item 系统可以存储用户的基本信息，如送货地址、用户名、手机号等
    \item 能够通过一个界面浏览商家、食品，并按照自己的喜好进行选择
    \item 可以选择食品，且同一种食品可以选择多个
    \item 选择的食品进入用户的购物车，并显示价格
    \item 用户能够地址管理，可以添加和删除多个地址
    \item 下单时可以选择地址列表里的一个地址，可以在下单页面进行修改
    \item 下单后订单信息可以在订单页面中查看
    \item 用户和商家所有信息储存在数据库上
\end{itemize}


\subsection{页面功能需求}
各页面的功能要求如下：
\begin{enumerate}[label={(\arabic*)}]
    \item 首页页面：本页面要求能够显示显示点餐分类信息和商家信息，搜索框在屏幕向下滚动时
    要求固定在顶部，底部菜单要求固定底部，并且点击点餐分类小图片，跳转到
    商家列表页面、点击首页可以跳转至首页页面，点击订单可以跳转至我的订单页面； 

    \item 商家列表页面：本页面要求根据点餐分类显示商家列表信息，如果处于登录状态，
    那些需要查询购物车中是否有此商家的食品。如果有，在页面上显示食品数量。
    点击某个商家可以跳转至对应的商家信息页面，且有底部菜单；
    
    \item 商家信息页面：本页面要求能够显示后台商家详细信息及所属食品信
    息，并自动计算总价。若未登录，当用户点
    击添加食品时强制跳转至登陆页面，若已登录，要求能够正常增减购物车中的食品。
    点击“去结算”按钮，跳转到确认订单页面；

    \item 历史订单页面：显示用户历史订单信息，包括已支付订单和未支付订单。
    点击某个历史订单，可以对订单明细信息进行显示和隐藏。
    点击未支付订单右侧“去支付”按钮，跳转到支付界面；
    
    \item 登录页面：本页面要求用户输入错误的用户名或密码后点击登录会无法登录并提示错误
    ，若用户名和密码正确则能够登录并返回上一个页面，点击去注册则可以跳转至注册页面；
    
    \item 注册页面：本页面要求用户输入用户名时若用户名已存在则做出提示并无法注册，如果用户
    输入错误的手机号，则会提示手机号输入错误在填写完全部信息后点击注册可以成功注册并返回
    登陆页面；
    
    \item 确认订单页面：本页面要求能够显示用户的地址信息和购物车中的订单信息，用户第一
    次进入时没有默认地址并显示“请选择默认地址”，有默认地址则显示默认地址，点击送货地址可
    以跳转至送货地址列表页面，点击去支付可以跳转至在线支付页面；
    
    \item 送货地址列表页面：本页面要求能够显示用户已有的送货地址，
    点击某个送货地址，跳转回确认订单页面、点击“新增”按钮，跳转到新增送货地址页面、
    点击“编辑”按钮，跳转到送货地址编辑页面、点击“删除”按钮，删除此送货地址；
    
    \item 支付页面：本页面要求能够显示用户的订单信息，并且能够选择显示和隐藏，默认
    隐藏，并且要求阻止用户返回确认订单页面，防止重复添加订单，可以点击确认支付，
    跳转到付款码界面，完成支付

\end{enumerate}



\subsection{非功能性需求}


\subsubsection{接口}
向前端提供的接口必须和项目三一致，使得项目三的前端不经过任何修改就可以
跟本项目的后端工作。

\subsubsection{界面}
因为采用项目三的前端，所以本项目对界面没有任何要求。

\section{软件架构}

根据项目任务书的要求，本项目需要使用 Spring boot技术
实现，对项目的架构没有要求。通过观看教学视频和阅读教学课件我们还是决定
采用项目三中的MVC架构，以便将项目三的前端直接拿来用。

项目主要分为以下模块：
\begin{enumerate}[label={(\arabic*)}]
    \item View层：前端网页。用户通过网页浏览器访问网页，通过点击和输入
    向后端服务器发送HTTP请求。
    \item 前端控制器：负责拦截、过滤、格式化、转发请求到对应的Controller，进行
    处理后，将响应返回给客户的浏览器。在本项目中我们无需编写前端控制器，只需要在
    MAVEN中添加相应的依赖即可。
    \item Po层：储存每个数据库中每个表所包含的列。
    \item Controller层：采用 SpringBoot 框架，Spring 检测到某一个类。
    有@Controller注解，便会自动将其注册为Controller。服务器运行时如果接收到
    一个HTTP请求，便会解析URL中的PATH，封装请求参数，将其传递到对应的Conctroller中。
    Controller调用对应的Service层的接口，进行进一步的处理。
    \item Service层：业务逻辑放在这一层中，调用对应的Mapper层的方法，对数据库中的
    若干表进行业务相关的操作，并包含impl层，在该层实现具体方法。
    \item Mapper层：相当于项目三中的Dao层，mapper层直接与数据库打交道（执行SQ
    L语句），接口提供给service层。
\end{enumerate}

经过这样的架构设计我们的后端服务器可以
很好的跟项目三的前端对接。在后端开发的过程中，我们也能通过分工提高开发效率。

\section{软件设计}
\subsection{数据库设计} \label{section:pr4_shujukusheji}
数据库采用MySql数据库。 编写Sql脚本创建数据库和表，并导入
一些数据用于测试。 使用Navicat 16 for MySql来查看和管理数据库。 基于需求
分析，我们设计七个数据库表：商家表(Business)、食品表(Food)、购物车表(Cart)、订单表(Orders)、
订单明细表(OrdersDetailet)、 用户表(User)、 地址表(DeliveryAddress)。

\subsection{Contorller层设计}
前端控制器根据URL调用生成对应的Controller对象，调用它对应的方法。Controller
负责调用对应Service层的接口方法。此项目接口后期升级为restful风格，参见本文档的附录接口文档。

\subsection{Service层设计}
跟项目三相同，我们采用了基于接口的设计方法。参见本文档\ref{subsection:PR3-service}部分。


\subsection{Mapper层设计}
Mapper层只需设计接口，为接口添加相应的注解就可以完成
跟项目三Dao层一样的操作。一些复杂的SQL操作无法通过注解来实现的话我们可以
添加XML文件来实现。所以以下给出Mapper层的接口设计，具体实现请浏览项目代码。


\section{项目团队与分工}
杨乐：点餐业务流一： 
(1) 根据点餐分类查询商家 
(2) 根据商家编号查询商家 
(3) 根据商家编号查询所属食品信息 
(4) 登录 
(5) 查询购物车中的食品信息 
(6) 向购物车中添加记录 ；
其他业务流： 
(1) 查询历史订单 
文档编写

郑宇轩：点餐业务流二： 
(1) 购物车表更新 
(2) 从购物车删除一条记录 
(3) 根据用户编号查询送货地址 
(4) 创建订单 
(5) 查询订单信息 ；
其他业务流： 
(1) 送货地址的增删改查 
(2) 手机号码是否已注册验证 
文档编写


\section{项目技术}
本项目继续采用MVC架构，使用SpringBoot和MyBatis技术重构项目三的后端。
\subsection{代码共享}
本项目由四个人开发，使用GIT做项目管理，远程仓库使用gitee。
gitee远程仓库的地址为：

https://gitee.com/cloudoftwilight/elb.git


约定每次开始编码前使用git pull命令同步代码。每一次编码结束使用git commit和git push命令上传代码
至远程仓库。使用git commit命令需要添加-m选项为
该次上传添加注释，注释中必须简要说明完成了哪个部分、修复了哪个Bug等。

\subsection{开发环境}
本项目使用SpringBoot + MyBatis + MySql技术进行开发。使用Spring Tool
Suite作IDE，使用MAVEN做依赖管理。下面给出项目pom.xml文件内主要添加的内容。

\begin{lstlisting}[ language=xml]
         
         <dependencies>
             <dependency>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-starter</artifactId>
             </dependency>
             
             <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>dashscope-sdk-java</artifactId>
                <exclusions>
                    <exclusion>
                        <groupId>org.slf4j</groupId>
                        <artifactId>slf4j-simple</artifactId>
                    </exclusion>
                </exclusions>
                <version>2.8.3</version>
            </dependency>
             
             <dependency>
                <groupId>com.hankcs</groupId>
                <artifactId>hanlp</artifactId>
                   <version>portable-1.8.4</version>
            </dependency>
             
             <dependency>
                <groupId>com.auth0</groupId>
                <artifactId>java-jwt</artifactId>
                <version>3.10.3</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml</artifactId>
                <version>4.1.2</version>
            </dependency>
             
             <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>5.8.32</version>
            </dependency>
            
             <dependency>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-starter-web</artifactId>
             </dependency>
             
             <dependency>
                 <groupId>org.mybatis.spring.boot</groupId>
                 <artifactId>mybatis-spring-boot-starter</artifactId>
                 <version>2.0.1</version>
             </dependency>
             
             <dependency>
                 <groupId>mysql</groupId>
                 <artifactId>mysql-connector-java</artifactId>
                 <version>5.1.49</version>
                 <scope>runtime</scope>
             </dependency>
             
             <dependency>
                <groupId>org.jsoup</groupId>
                <artifactId>jsoup</artifactId>
                <version>1.14.1</version> 
                </dependency>
             
             <dependency>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-starter-test</artifactId>
                 <scope>test</scope>
                 <exclusions>
                     <exclusion>
                        <groupId>org.junit.vintage</groupId>
                         <artifactId>junit-vintage-engine</artifactId>
                     </exclusion>
                 </exclusions>
             </dependency>
         </dependencies>
         
    
\end{lstlisting}

\subsection{Controller层}
本项目的Controller层的实现比项目三更简单，其作用只有调用对应的
Service层接口。下面给出一个Controller层方法的代码作为例子。

\begin{lstlisting}[ language=java]
@RestController
@RequestMapping("/FoodController")
public class FoodController {
    @Autowired
    private FoodService foodService;
    @RequestMapping("/listFoodByBusinessId")
    public List<Food> listFoodByBusinessId(Food food) throws Exception {
        return foodService.listFoodByBusinessId(food.getBusinessId());
    }
}    
\end{lstlisting}

其中@RestController是SpringBoot框架提供的注解。它可以自动帮我们
注册这个Controller类。@RequestMapping这个注解是对请求URL上的路径
进行映射，上面的listFoodByBusinessId对应的就
是/elm/FoodController/listFoodByBusinessId这样的请求路径。

\subsection{Service层}
通过使用SpringBoot框架Service层的实现也变得很简单，下面给出一个Service
接口的实现作为例子。
\begin{lstlisting}[ language=java]
    @Service
    public class FoodServiceImpl implements FoodService {
    
        @Autowired
         private FoodMapper foodMapper;
         @Override
         public List<Food> listFoodByBusinessId(Integer businessId) {
         return foodMapper.listFoodByBusinessId(businessId);
         }
    
    }
\end{lstlisting}

@Service注解把类注册到了Spring容器内；添加@Autowired会自动创建对应的
实现类的对象。

\subsection{Mapper层}
我们同样给出一个Mapper作为例子。
\begin{lstlisting}[ language=java]
@Mapper
public interface FoodMapper {
	@Select("select * from food where businessId=#{businessId} and valid = 1 order by foodId")
	public List<Food> listFoodByBusinessId(Integer businessId);
	@Select("select * from food where foodId=#{foodId}")
	public Food getFoodById(Integer foodId);
}
\end{lstlisting}

其中@Mapper注解把接口注册到Spring容器内，@Select注解对应的就是这个
接口函数被调用时执行的SQL语句。如果执行的数据库操作较复杂，无法用
注解实现，则编写对应的XML文件即可。

\section{项目部署}
本项目由于采用的是SpringBoot框架，因此只需要在STS上导入项目，
等待MAVEN自动下载配置对应的依赖即可。接下来给出相应的步骤。

\subsubsection{数据库的准备}

\begin{enumerate}[label={(\arabic*)}]
    \item 确保mysql数据库root账户的密码修改为"123456"后进行后续操作。
    \item 打开Navicat，如没有需从智慧树平台进行下载安装
    \item 点击左上角的“连接”按钮，点击“MySQL”，出现以下界面:
    

按照上图进行输入，然后点击“确定”。
    \item 点击上方的“新建查询”，将elm.sql里的文本全部复制进来，点击“运行”
    \item 如果出现下图所示的数据库和表项代表数据库准备完毕

\end{enumerate}

\subsection{导入项目}
打开STS，点击import project,选择existing project into workspace，
选择仓库目录下的back目录，点击"Finish"，如下图所示。

这样就完成了项目的导入，接下来等待右下方的进度条消失即可运行项目。
